using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Diagnostics;
using System.Windows.Ink;
using AgilePlannerDT.Display.Impl;
using AgilePlannerDT.Data.Impl;
using AgilePlannerDT.Data;
using AgilePlannerDT.Display;
using AgilePlannerDT.Display.Events;
using AgilePlannerDT.Utils;
using System.Collections.ObjectModel;
using AgilePlannerDT.Persister;
using AgilePlannerDT.Persister.Impl;
using AgilePlannerDT.Persister.Impl.File;
using AgilePlannerDT.Persister.Impl.Webservice;
using System.ComponentModel;
using AgilePlannerDT.Application;
using System.Speech;
using System.Speech.Recognition;
using System.Windows.Threading;
using System.Reflection;
using AgilePlannerDT.Application.Modules;
using AgilePlannerDT.Application.Modules.Impl;
using System.Timers;
using System.Threading;
using System.Globalization;
using AgilePlannerDT.Application.Commands;
using AgilePlannerDT.Application.Commands.Impl;
using AgilePlannerDT.Persister.Impl.Socket;
using System.Text.RegularExpressions;
using System.Net.Sockets;
using SBSDKComWrapperLib;
using System.Windows.Interop;
using libSMARTMultiTouch.Table;

namespace AgilePlannerDT
{
    /// <summary>
    /// Interaction logic for AgilePlannerMainWindow.xaml
    /// </summary>
    /// 

    public partial class AgilePlannerMainWindow : System.Windows.Window, AgilePlannerApplication
    {
        #region Attributes

        private bool _sendMouseMoveInfo = false;
        private const int FIRST_TOUCH_ID = 1;
        private Dictionary<long, DisplayObject> cards = new Dictionary<long, DisplayObject>();
        private Dictionary<Dictionary<int,int>, MousePointer> mouses = new Dictionary<Dictionary<int,int>, MousePointer>();
        private List<Dictionary<int, int>> deletedKey = new List<Dictionary<int, int>>();
        private DisplayObject activeCard, selectedCard;
        private readonly int NUM_SKIP_MOUSE_MOVE = 5;
        private int mouseMoveNumber = 0;
        private int secondMouseMoveNumber = 0;
        private Point basePoint = new Point(0, 0);
        private List<ApCommand> commands = new List<ApCommand>();

        private Color defaultColor = CardConstants.YELLOW;

        private bool isLoadingPhase = false;
        private bool areCardsHighlighted = false;
        private System.Timers.Timer cardsHighlightedTimer;

        GestureRecognizer gestureRecognizer;
      //  GestureRecognizer m_Recognizer;

    //    private MouseDevice mouse;
        //private InkPresenter inkPresenter;
        //private Stroke gestureStroke;


        private SpeechModule speechModule;
        private GestureModule gestureModule;
        private PersisterModule persisterModule;
        private IndexCardEventHandlerModule eventModule;

        private FloatingToolBox ftoolbox;

        //Dot voting
        private bool votingEnabled = false;

        #endregion

        #region SMARTBoard SDK

        private ISBSDKBaseClass2 isbSDKBaseClass2;
        private _ISBSDKBaseClass2Events_Event isbSDKEvents;
        private int MultiTouchHandler = 0;
        const int MAXGESTURES = 5;
        private double offsetX = 1;
        private double offsetY = 1;
        private bool isMultiTouchEnabled = true;
        private DisplayObject mouseEventActivatedCard = null;
        int[] StrokeToIdMapping;
        Stroke[] GestureStrokes;
        Collection<Line>[] gestureLines;
        Dictionary<int, DisplayObject> touchCardMapping;
        public delegate ReadOnlyCollection<GestureRecognitionResult> RecognizeText(StrokeCollection sc);
        public delegate Stroke CreateStroke(Point P);
        public delegate void drawStroke(Point start, Point end,Collection<Line> lineCollection);
        public delegate void removeStroke(Collection<Line> lineCollection);
        public delegate void processGesture(object sender, InkCanvasGestureEventArgs e);
        public delegate DisplayObject getPosition(Point point);
      //  public delegate Point GetRelativePoint(Point p, UIElement element);
        public delegate void OnTouchEvent(Point p);

        public int firstTouchX=-1, firstTouchY=-1, secondTouchX=-1,secondTouchY=-1, firstTouchID=0;
        #endregion

        #region Constructor

        public AgilePlannerMainWindow()
        {
                      
            InitializeComponent();
            //initialize the SMARTBoard SDK
            try
            {
                isbSDKBaseClass2 = new SBSDKBaseClass2();
               
                isbSDKEvents = (_ISBSDKBaseClass2Events_Event)isbSDKBaseClass2;
                isbSDKEvents.OnXYDown += new _ISBSDKBaseClass2Events_OnXYDownEventHandler(m_TouchHandler_ContactDown);
                isbSDKEvents.OnXYUp += new _ISBSDKBaseClass2Events_OnXYUpEventHandler(m_TouchHandler_ContactUp);
                isbSDKEvents.OnXYMove += new _ISBSDKBaseClass2Events_OnXYMoveEventHandler(m_TouchHandler_ContactMove);
                StrokeToIdMapping = new int[MAXGESTURES];
                gestureLines = new Collection<Line>[MAXGESTURES];
                GestureStrokes = new Stroke[MAXGESTURES];
                touchCardMapping = new Dictionary<int, DisplayObject>();

                for (int i = 0; i < MAXGESTURES; ++i)
                {

                    StrokeToIdMapping[i] = -1;
                    gestureLines[i] = new Collection<Line>();
                }
            }
            catch (Exception e)
            {
                //If we cannot load the SMARTBoard SDK, then start app as desktop version
                Console.WriteLine("DEBUG: Multitouch disabled");
                this.isMultiTouchEnabled = false;
            }

            //end of initalization

            Properties.Settings.Default.Reload();
            //make the application start in fullscreen mode
            this.Width = System.Windows.SystemParameters.VirtualScreenWidth;
            //this.Height = System.Windows.SystemParameters.WorkArea.Height;
            this.Height = System.Windows.SystemParameters.VirtualScreenHeight;
            this.Left = 0;
            this.Top = 0;
            //should help to get rid of the accidential resizing
            //when you touch close to the border of the window
            this.ResizeMode = ResizeMode.NoResize;
            

            gestureRecognizer = new GestureRecognizer();
            if (this.isMultiTouchEnabled)
            {
                gestureRecognizer.SetEnabledGestures(new ApplicationGesture[] { ApplicationGesture.AllGestures, });
                gestureModule = new GestureModuleImpl(this, this.Dispatcher, this.gestureRecognizer);
             }  
            else
              gestureModule = new GestureModuleImpl(this, this.Dispatcher, this.surface, this.gestureRecognizer);
              
            eventModule = new IndexCardEventHandlerModuleImpl(this, this.Dispatcher, this.windowCanvas, this.gestureModule);
           
            //set the default size of the cards, iterations, text areas and floating boxes according to the scale 
            //activate speech recognition
            if (Properties.Settings.Default.SpeechRecognitionEnabled)
            {
                try
                {
                    speechModule = new SpeechModuleImpl(this, this.Dispatcher);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.StackTrace);
                    Properties.Settings.Default.SpeechRecognitionEnabled = false;
                }
            }

            cardsHighlightedTimer = new System.Timers.Timer(2000);
            cardsHighlightedTimer.Elapsed += new ElapsedEventHandler(cardsHighlightedTimer_Elapsed);
        
            ftoolbox = new FloatingToolBox(this);
            ftoolbox.OnWebServiceURLChanged += new FloatingToolBox.WebServiceURLChangedEventHandler(FloatingToolbox_OnWebServiceURLChanged);
            ftoolbox.OnDisconnectButtonClicked += new FloatingToolBox.DisconnectButtonClickedEventHandler(FloatindToolbox_OnDisconnectButtonClicked);
            windowCanvas.Children.Add(ftoolbox);

            
           
        }

        private delegate void HighlightDelegate();

        #endregion

        #region initalize Multitouch when the canvas is activated
        protected override void OnActivated(EventArgs e)
        {
            base.OnActivated(e);
           
            if (this.isMultiTouchEnabled&&MultiTouchHandler == 0)
            {
                WindowInteropHelper windowInterOpHelper = new WindowInteropHelper(GetWindow(this));
                MultiTouchHandler = windowInterOpHelper.Handle.ToInt32();

                isbSDKBaseClass2.SBSDKAttach(MultiTouchHandler, false);
                isbSDKBaseClass2.SBSDKSetSendMouseEvents(MultiTouchHandler, _SBCSDK_MOUSE_EVENT_FLAG.SBCME_NEVER, -1);
            }
        }
        #endregion

        #region Custom Event Handling

        #region Children Event Handling

        private void cardsHighlightedTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            cardsHighlightedTimer.Stop();

            this.Dispatcher.Invoke(DispatcherPriority.Render, new HighlightDelegate(Highlight));
        }

        private void DisplayObject_OnFadeOutCompleted(DisplayObject sender)
        {
            DisplayObject parent;

            if (sender is StoryCardDisplayObject)
            {
                if (cards.TryGetValue(sender.ParentID, out parent))
                {
                    if (parent is IterationDisplayObject)
                    {
                        ((IterationDisplayObject)parent).RemoveStoryCard((StoryCardDisplayObject)sender);
                    }
                }
            }

            windowCanvas.Children.Remove((UIElement)sender);

            SelectedCard = Next();
        }

        #endregion

        #region Toolbox

        private void FloatindToolbox_OnDisconnectButtonClicked()
        {
            this.Clear();
            if (Persister != null)
            {
                if (Persister is AsyncXMLSocketPersister)
                    ((AsyncXMLSocketPersister)Persister).stop();//close the inbound and outbound thread
                Persister.RemovePlannerDataChangeListener(persisterModule);
            }
            persisterModule = new PersisterModuleImpl(this, this.Dispatcher,
                    new AsyncWrapperPersister(new SyncPersisterToXML()));
        }

        private void FloatingToolbox_OnWebServiceURLChanged(string uri)
        {
            if (Persister != null)
            {
                if (Persister is AsyncXMLSocketPersister)
                    ((AsyncXMLSocketPersister)Persister).stop();//close the inbound and outbound thread
                Persister.RemovePlannerDataChangeListener(persisterModule);
            }

            if (uri.Equals("localhost"))
            {
                persisterModule = new PersisterModuleImpl(this, this.Dispatcher,
                    new AsyncWrapperPersister(new SyncPersisterToXML()));
            }
            else
            {
                int port = 5555;
                string url="";
                try
                {
                  url  = analyzeURI(uri, out port);
                }
                catch
                {
                    throw new FormatException();
                   
                }
                try
                {
                    persisterModule = new PersisterModuleImpl(this, this.Dispatcher,
                        new AsyncXMLSocketPersister(new SocketConnection(url, port), this.Dispatcher));
                }
                catch (SocketException e)
                {
                    throw e;
                }
                
            }

            Persister.AddPlannerDataChangeListener(persisterModule);
            ftoolbox.Persister = Persister;
        }

        #endregion

        #region Main Window

        protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
        {
            base.OnMouseLeftButtonUp(e);

            if (activeCard != null)
            {
                activeCard.ForwardMouseLeftButtonUp(e);
                activeCard = null;
            }
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            if (activeCard != null)
           {
                activeCard.ForwardMouseMove(e);
            }
            else
                if (Persister is AsyncXMLSocketPersister && SendMouseMoveInfoEnabled)
                {
                    if (this.mouseMoveNumber == this.NUM_SKIP_MOUSE_MOVE)
                    {
                        Persister.MouseMove(new MouseMoveDataObject(0, 0,"APDT", e.GetPosition(this.windowCanvas).X / Properties.Settings.Default.Scale, e.GetPosition(this.windowCanvas).Y / Properties.Settings.Default.Scale, MouseMoveConstants.PURE_MOUSEMOVE, 0L));
                        this.mouseMoveNumber = 0;
                    }
                    else
                    {
                        this.mouseMoveNumber++;
                    }
                }
           
        }

        #endregion

        #endregion

        #region AgilePlannerApplication Members

        #region Properties

        public bool SendMouseMoveInfoEnabled
        {
            get { return this._sendMouseMoveInfo; }
            set { this._sendMouseMoveInfo = value; }
        }

        public DisplayObject ActiveCard
        {
            get { return this.activeCard; }
            set { this.activeCard = value; }
        }

        public Dictionary<long, DisplayObject> Cards
        {
            get { return this.cards; }
            set { this.cards = value; }
        }

        public DisplayObject ToolBox
        {
            get { return this.ftoolbox; }
        }
        public List<ApCommand> Commands
        {
            get { return this.commands; }
        }

        public Color DefaultColor
        {
            get { return defaultColor; }
            set
            {
                defaultColor = value;

                if ((SelectedCard != null) && (SelectedCard is StoryCardDisplayObject))
                {
                    ((StoryCardDisplayObject)SelectedCard).CardColor = value;
                }
            }
        }

        public bool IsLoadingPhase
        {
            get { return isLoadingPhase; }
            set { isLoadingPhase = value; }
        }

        public bool IsVotingEnabled
        {
            get;
            set;
        }

        public AsynchronousPersister Persister
        {
            get
            {
                if (persisterModule != null)
                    return this.persisterModule.Persister;
                else
                    return null;
            }
            set { this.persisterModule.Persister = value; }
        }

        public Project Project
        {
            get
            {
                if (persisterModule != null)
                    return persisterModule.Project;
                else
                    return null;
            }
            set { persisterModule.Project = value; }
             
        }

        public DisplayObject SelectedCard
        {
            get { return this.selectedCard; }
            set
            {
                if (this.selectedCard != null)
                    this.selectedCard.Select();

                this.selectedCard = value;

                if (this.selectedCard != null)
                    this.selectedCard.Select();
            }
        }

        #endregion

        #region Functions

        public void AddCommand(ApCommand command)
        {
            //search the list with command to see if the new one is
            //already in there (maybe this is just an undo/redo so it
            //shouldn't be added again
        }

        public void BringToFront(DisplayObject sender)
        {
            if (sender is StoryCardDisplayObject)
            {
                StoryCardDisplayObject storycard = (StoryCardDisplayObject)sender;

                DisplayObject dobj;
                if (cards.TryGetValue(storycard.ParentID, out dobj))
                {

                    if (dobj is IterationDisplayObject)
                    {
                        IterationDisplayObject iteration = (IterationDisplayObject)dobj;

                        //assures that the storycards will reappear in the right order
                        //on reload
                        iteration.RemoveStoryCard(storycard);
                        iteration.AddStoryCard(storycard);
                    }
                }

                windowCanvas.Children.Remove((UIElement)sender);
                windowCanvas.Children.Add((UIElement)sender);
            }
            else if (sender is IterationDisplayObject)
            {
                IterationDisplayObject iteration = (IterationDisplayObject)sender;

                foreach (StoryCardDisplayObject sc in iteration.StoryCardChildren)
                {
                    windowCanvas.Children.Remove((UIElement)sc);
                }

                windowCanvas.Children.Remove((UIElement)sender);
                windowCanvas.Children.Add((UIElement)sender);

                foreach (StoryCardDisplayObject sc in iteration.StoryCardChildren)
                {
                    windowCanvas.Children.Add((UIElement)sc);
                }

            }
            else
            {
                windowCanvas.Children.Remove((UIElement)sender);
                windowCanvas.Children.Add((UIElement)sender);
            }

            //the floating toolbox is always on top of everything
            windowCanvas.Children.Remove(ftoolbox);
            windowCanvas.Children.Add(ftoolbox);
        }

        public void Clear()
        {
            windowCanvas.Children.Clear();
            cards.Clear();
            windowCanvas.Children.Add(ftoolbox);
        }

        // Edited 10.July.2008 to accomodate StateAreas.
        public IterationDisplayObject CreateIteration(Iteration iteration)
        {
            if (iteration.Name == "Default StateArea")
            {
                StateAreaDisplayObjectImpl iter = new StateAreaDisplayObjectImpl(iteration, this);

                //register event listeners
                iter.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(eventModule.PreviewMouseLeftButtonDownHandler);
                iter.PreviewMouseLeftButtonUp += new MouseButtonEventHandler(eventModule.PreviewMouseLeftButtonUpHandler);
                iter.PreviewMouseMove += new MouseEventHandler(eventModule.PreviewMouseMoveHandler);
                iter.IterationData.PropertyChanged += new PropertyChangedEventHandler(eventModule.PropertyChangedHandler);
                iter.OnIndexCardDropped += new DisplayObjectImpl.IndexCardDroppedEventHandler(eventModule.IndexCardDropHandler);
                iter.OnFadeOutCompleted += new DisplayObjectImpl.FadeOutCompletedEventHandler(DisplayObject_OnFadeOutCompleted);

                //add the iteration to the lookup and the canvas
                cards.Add(iter.ID, iter);
                windowCanvas.Children.Add(iter);

                SelectedCard = iter;

                return iter;
            }
            else
            {
                IterationDisplayObjectImpl iter = new IterationDisplayObjectImpl(iteration, this);

                //register event listener
                iter.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(eventModule.PreviewMouseLeftButtonDownHandler);
                iter.PreviewMouseLeftButtonUp += new MouseButtonEventHandler(eventModule.PreviewMouseLeftButtonUpHandler);
                iter.PreviewMouseMove += new MouseEventHandler(eventModule.PreviewMouseMoveHandler);
                iter.IterationData.PropertyChanged += new PropertyChangedEventHandler(eventModule.PropertyChangedHandler);
                iter.OnIndexCardDropped += new DisplayObjectImpl.IndexCardDroppedEventHandler(eventModule.IndexCardDropHandler);
                iter.OnFadeOutCompleted += new DisplayObjectImpl.FadeOutCompletedEventHandler(DisplayObject_OnFadeOutCompleted);

                //add the iteration to the lookup and the canvas
                cards.Add(iter.ID, iter);
                windowCanvas.Children.Add(iter);

                //resize it
                /*         double startupWidth = iteration.Width - CardConstants.ITERATION_DEFAULT_WIDTH;
                         double startupHeight = iteration.Height - CardConstants.ITERATION_DEFAULT_HEIGHT;

                         iter.Resize(startupWidth > 0 ? startupWidth : 0,
                             startupHeight > 0 ? startupHeight : 0);
                         */
                SelectedCard = iter;

                return iter;
            }
        }

        public StoryCardDisplayObject CreateStoryCard(StoryCard storycard)
        {
            StoryCardDisplayObjectImpl sc = new StoryCardDisplayObjectImpl(storycard, this, storycard.Background);
            sc.Opacity = 1;
            //register event listeners
            sc.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(eventModule.PreviewMouseLeftButtonDownHandler);
            sc.PreviewMouseLeftButtonUp += new MouseButtonEventHandler(eventModule.PreviewMouseLeftButtonUpHandler);
            sc.PreviewMouseMove += new MouseEventHandler(eventModule.PreviewMouseMoveHandler);
            sc.OnIndexCardDropped += new DisplayObjectImpl.IndexCardDroppedEventHandler(eventModule.IndexCardDropHandler);
            sc.StoryCardData.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(eventModule.PropertyChangedHandler);
            sc.OnFadeOutCompleted += new DisplayObjectImpl.FadeOutCompletedEventHandler(DisplayObject_OnFadeOutCompleted);

            //add sc to lookup and canvas
            cards.Add(sc.ID, sc);
            windowCanvas.Children.Add(sc);
/*
            //resize it
            double startupWidth = storycard.Width - CardConstants.STORYCARD_DEFAULT_WIDTH;
            double startupHeight = storycard.Height - CardConstants.STORYCARD_DEFAULT_HEIGHT;

            sc.Resize(startupWidth > 0 ? startupWidth : 0,
                startupHeight > 0 ? startupHeight : 0);
            */
     //       if this card is a TextArea
            if(storycard.Background.Equals(CardConstants.TRANSPARENT))
            {
                sc.switchStoryCardToTextArea();
            }
            SelectedCard = sc;

            return sc;
        }

        public DisplayObject Delete()
        {
            return Delete(SelectedCard);
        }

        public DisplayObject Delete(DisplayObject card)
        {
            if (card is IterationDisplayObject)
            {
                commands.Add(new IterationDeleteCommand(this, (Iteration)((IterationDisplayObject)card).IterationData.Clone()));
                //                card.g
                Persister.DeleteIteration(card.ID);
            }
            else if (card is StoryCardDisplayObject)
            {
                commands.Add(new StoryCardDeleteCommand(this, (StoryCard)((StoryCardDisplayObject)card).StoryCardData.Clone()));
                Persister.DeleteStoryCard(card.ID);
            }

            return card;
        }

        public double GetHeight()
        {
            //if (ActualHeight == 0)
            //    return Height;
            //else
            //    return ActualHeight;

            return Math.Max(ActualHeight, Height);
        }

        public double GetWidth()
        {
            //if (ActualWidth == 0)
            //    return Width;
            //else
            //    return ActualWidth;

            return Math.Max(ActualWidth, Width);
        }

        public void Highlight()
        {
            foreach (DisplayObject card in cards.Values)
            {
                card.Highlight();
            }

            if (!areCardsHighlighted)
            {
                cardsHighlightedTimer.Start();
                areCardsHighlighted = true;
            }
            else
            {
                areCardsHighlighted = false;
            }
        }

        public DisplayObject Next()
        {
            if (SelectedCard != null)
            {
                long currentID = SelectedCard.ID;
                if (cards.Count == 0)
                    return null;
                else
                {
                    do{
                       if(cards.GetEnumerator().Current.Key != currentID)
                           return cards.GetEnumerator().Current.Value;
                    }while(cards.GetEnumerator().MoveNext());
                   
                }
            }
            return null;


/*               for(cards.Keys)
            if (SelectedCard != null)
            {
                long currentID = SelectedCard.ID;

                //try to find a higher ID
                for(DisplayObject  card in )
                for (long i = currentID + 1; i < 1000; i++)
                {
                    if (cards.ContainsKey(i))
                    {
                        DisplayObject card;
                        if (cards.TryGetValue(i, out card))
                        {
                            SelectedCard = card;
                            return SelectedCard;
                        }
                    }
                }

                //if none found try a lower one
                for (long i = currentID - 1; i > 0; i--)
                {
                     
                    if (cards.ContainsKey(i))
                    {
                        DisplayObject card;
                        if (cards.TryGetValue(i, out card))
                        {
                            SelectedCard = card;
                            return SelectedCard;
                        }
                    }
                }
            }
            return null;*/
        }

        public DisplayObject Previous()
        {
            if (SelectedCard != null)
            {
                long currentID = selectedCard.ID;

                //try to find a lower id
                for (long i = currentID - 1; i > 0; i--)
                {
                    if (cards.ContainsKey(i))
                    {
                        DisplayObject card;
                        if (cards.TryGetValue(i, out card))
                        {
                            SelectedCard = card;
                            return SelectedCard;
                        }
                    }
                }

                //if none found try to find a higher one
                for (long i = 1000; i > currentID - 1; i--)
                {
                    if (cards.ContainsKey(i))
                    {
                        DisplayObject card;
                        if (cards.TryGetValue(i, out card))
                        {
                            SelectedCard = card;
                            return SelectedCard;
                        }
                    }
                }
            }
            return null;
        }

        public bool TryFindIteration(Point p, out IterationDisplayObject value)
        {
            foreach (DisplayObject card in cards.Values)
            {
                if (card is IterationDisplayObject)
                {
                    if (card.Contains(p))
                    {
                        value = (IterationDisplayObject)card;
                        return true;
                    }
                }
            }

            value = null;
            return false;
        }

        #endregion

            #region internal help function
        // return IP and port from a valid uri
        private string analyzeURI(string uri, out int port)
        {
            Regex r = new Regex(":");
            string[] target = r.Split(uri);
            if (target.Length == 1)
            {
                port = 5555;
                return target[0];
            }
            else
            {
              try{
                    port = Int32.Parse(target[1]);
                    return target[0];
                  }catch{
                      throw new FormatException();
                  }
            }
        }
        #endregion
     
        #endregion

        #region AgilePlannerApplication Members

        public bool isRemoteMouseExisted(MouseMove move)
        {
        //    Dictionary<int, int> keys = new Dictionary<int, int>();
        //    keys.Add(move.ClientID, move.TouchID);
            foreach (Dictionary<int, int> keys in mouses.Keys)
            {
                if (keys.ContainsKey(move.ClientID) && keys.ContainsValue(move.TouchID))
                    return true;
            }
            return false;
        }

        public void CreateRemoteMouse(MouseMove move)
        {
            MousePointer mouse = new MousePointer(move,this);
            Dictionary<int, int> keys = new Dictionary<int, int>();
            keys.Add(move.ClientID, move.TouchID);
            mouses.Add(keys,mouse );
            windowCanvas.Children.Add(mouse);
            mouse.FadeIn();
          

        }

        public void UpdateRemoteMouse(MouseMove move)
        {
            MousePointer pointer = null;
          //  Dictionary<int, int> keys = new Dictionary<int, int>();
          //  keys.Add(move.ClientID, move.TouchID);
            foreach(Dictionary<int,int> keys in mouses.Keys)
            {
              if(keys.ContainsValue(move.TouchID)&&keys.ContainsKey(move.ClientID))
                mouses[keys].Update(move);
              
            }
        }

        public void DeleteRemoteMouse(int client)
        {
            MousePointer pointer = null;
            
            foreach (Dictionary<int, int> keys  in mouses.Keys)
            {
                if (keys.ContainsKey(client) && mouses.TryGetValue(keys, out pointer))
                {
                    //    mouses.Remove(client);
                 //   mouses.Remove(keys);
                    deletedKey.Add(keys);
          //          mouses.
                    windowCanvas.Children.Remove(pointer);
                  
                }
            }

            foreach (Dictionary<int, int> shouldBeDeleted in deletedKey)
            {
                mouses.Remove(shouldBeDeleted);
            }
            deletedKey.Clear();
        }

      //  e.GetPosition(this.windowCanvas)
        public void SynchronizeResizingCard(DisplayObject card,Point p, int touchID)
        {
            if (Persister is AsyncXMLSocketPersister && SendMouseMoveInfoEnabled)
            {
                if (this.mouseMoveNumber == this.NUM_SKIP_MOUSE_MOVE)
                {

                    Persister.MouseMove(new MouseMoveDataObject(0, touchID, "APDT", p.X / Properties.Settings.Default.Scale, p.Y / Properties.Settings.Default.Scale, MouseMoveConstants.RESIZE_MOUSEMOVE, new CardSizeSynchronizationDataObject((long)card.ID, card.Width, card.Height)));
                    this.mouseMoveNumber = 0;
                }
                else
                {
                    this.mouseMoveNumber++;
                }
            }
        }

        public void SynchornizeMovingCard(DisplayObject card,Point p, int touchID)
        {
            
                if (Persister is AsyncXMLSocketPersister && SendMouseMoveInfoEnabled)
                {
                    if (this.mouseMoveNumber == this.NUM_SKIP_MOUSE_MOVE)
                    {

                        Persister.MouseMove(new MouseMoveDataObject(0, touchID, "APDT", p.X / Properties.Settings.Default.Scale, p.Y / Properties.Settings.Default.Scale, MouseMoveConstants.DRAG_MOUSEMOVE, new CardPositionSynchronizationDataObject((long)card.ID, card.LocationX / Properties.Settings.Default.Scale, card.LocationY / Properties.Settings.Default.Scale, card.RotationAngle)));
                        this.mouseMoveNumber = 0;
                    }
                    else
                    {
                        this.mouseMoveNumber++;
                    }
                }
            
        }
        #endregion

        #region AgilePlannerApplication Members


        public void HandleMouseMoveLoadedEvent(MouseMove move)
        {
            if (move.ThirdPartyObject is CardPoistionSynchronization)
            {
                CardPoistionSynchronization currentPosition = (CardPoistionSynchronization)(move.ThirdPartyObject);
                DisplayObject target = null;
                if (this.cards.TryGetValue((long)currentPosition.CardID, out target))
                {
                    if (target is StoryCardDisplayObject)
                    {
                        Console.WriteLine("orginialAngle:" + target.RotationAngle + "  " + "targetAngle: " + currentPosition.RotationAngle);
                        ((StoryCardDisplayObject)target).Move((currentPosition.X * Properties.Settings.Default.Scale - target.LocationX), (currentPosition.Y * Properties.Settings.Default.Scale - target.LocationY), (currentPosition.RotationAngle - target.RotationAngle));
                      //     ((StoryCardDisplayObject)target).Move((currentPosition.X - target.LocationX) , (currentPosition.Y - target.LocationY) , (currentPosition.RotationAngle - target.RotationAngle) );
                    }
                    if(target is IterationDisplayObject)
                    {
                        ((IterationDisplayObject)target).Move((currentPosition.X * Properties.Settings.Default.Scale - target.LocationX), (currentPosition.Y * Properties.Settings.Default.Scale - target.LocationY), (currentPosition.RotationAngle - target.RotationAngle));
                    }
                }
                
            }
            if (move.ThirdPartyObject is CardSizeSynchronization)
            {
                CardSizeSynchronization currentSize = (CardSizeSynchronization)(move.ThirdPartyObject);
                DisplayObject target = null;
                if (this.cards.TryGetValue((long)currentSize.CardID, out target))
                {
                    double dx = currentSize.Width - target.Width;
                    double dy = currentSize.Height - target.Height;
                    target.Resize(ref dx, ref dy);
                    ((DisplayObjectImpl)target).refitCardCenterAndAbsolutePosition(dx, dy);

                }
            }
        }

  

        #endregion

        #region Dot Voting

        public void EnableVoting(bool enable)
        {
            votingEnabled = enable;
        }

        public void ClearVoteDots()
        {
            foreach (KeyValuePair<long, DisplayObject> card in cards)
            {
                if (card.Value is StoryCardDisplayObject)
                {
                    ((StoryCardDisplayObject)card.Value).ClearVoteDots();
                }
            }

        }

        #endregion

        public Canvas getCanvas()
        {
            return this.windowCanvas;
        }

        #region MultiTouch MouseEvent
        void m_TouchHandler_ContactDown(int x, int y, int z, int ID)
        {
            if (touchCardMapping.Count == 0)
            {
                firstTouchX = x;
                firstTouchY = y;
                //no other cards activated, first touch
                Core.InputDevices.Mouse.Instance.Location = new System.Drawing.Point(x, y);
                Core.InputDevices.Mouse.LeftDown();
                firstTouchID = ID;
            }

            //if (ID == FIRST_TOUCH_ID)
            //{
            //    firstTouchX = x;
            //    firstTouchY = y;
            //    Core.InputDevices.Mouse.Instance.Location = new System.Drawing.Point((int)(x -10), (int)(y -10));
             
            //    Core.InputDevices.Mouse.LeftDown();
            //}

            //if (ID == 257)
            //{
            //    secondTouchX = x;
            //    secondTouchY = y;
            //}
            System.Windows.Point p = new System.Windows.Point(x * offsetX, y * offsetY);
            
            DisplayObject activatedCard = (DisplayObject)this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Render, new getPosition(getCurrentArtefact),(p));
            
            if (activatedCard != null)
            {
                //disable the second touch on the same artefact
                if (touchCardMapping.ContainsValue(activatedCard))
                {
                    return;
                }

                if (!touchCardMapping.ContainsKey(ID))
                {
                    touchCardMapping.Add(ID, activatedCard);
                }
                else
                {
                    touchCardMapping[ID] = activatedCard;
                }
                
                //if (ID == 257)
                //{
                    this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Render, new OnTouchEvent(activatedCard.OnTouchDown), p);
                //}

                //do not continue the gesture recognition
                return;
            }

            int  CurrentMapping = -1;
            for (int i = 0; i < MAXGESTURES; ++i)
            {
                if (StrokeToIdMapping[i] == -1)
                {
                    StrokeToIdMapping[i] = ID;
                    CurrentMapping = i;
                    break;
                }
            }
            if (-1 != CurrentMapping)
            {
                GestureStrokes[CurrentMapping] = (Stroke)this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Render, new CreateStroke(initializeInkStroke), p);    
            }
        }

        private int FindMappingIndex(int ID)
        {
            for (int i = 0; i < MAXGESTURES; ++i)
            {
                if (StrokeToIdMapping[i] == ID)
                {
                    return i;
                }
            }
            return -1;
        }

        private Stroke initializeInkStroke(Point p)
        {

            return new Stroke(new StylusPointCollection(new System.Windows.Point[] { p }));

        }

        void m_TouchHandler_ContactUp(int x, int y, int z, int ID)
        {
            if (ID == firstTouchID)
            {
                Core.InputDevices.Mouse.Instance.Location = new System.Drawing.Point(x, y);
                Core.InputDevices.Mouse.LeftUp();
            }

            //// first touch point
            //if (ID == FIRST_TOUCH_ID)
            //{
            //    firstTouchX = -1;
            //    firstTouchY = -1;
          
            //    Core.InputDevices.Mouse.LeftUp();
            //}
            //// second touch point
            //if (ID == 257)
            //{
            //    secondTouchX = -1;
            //    secondTouchY = -1;
            //}
           
            System.Windows.Point p = new System.Windows.Point(x * offsetX, y * offsetY);

            if (touchCardMapping.ContainsKey(ID)&&touchCardMapping[ID] != null)
            {
                DisplayObject activatedCard = touchCardMapping[ID];
                touchCardMapping.Remove(ID);

                //if (ID == 257)
                    this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Render, new OnTouchEvent(activatedCard.OnTouchUp),p);
                return;
            }

            int CurrentMapping = FindMappingIndex(ID);
            if (-1 != CurrentMapping)
            {
                StrokeToIdMapping[CurrentMapping] = -1;
                GestureStrokes[CurrentMapping].StylusPoints.Add(new StylusPoint(p.X, p.Y));
               
                StrokeCollection sc = new StrokeCollection();
                sc.Add(GestureStrokes[CurrentMapping]);
                ReadOnlyCollection<GestureRecognitionResult> results = (ReadOnlyCollection<GestureRecognitionResult>)this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Render, new RecognizeText(gestureRecognizer.Recognize), sc);
                if (results.Count > 0)
                {
                    this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Render, new processGesture(gestureModule.ProcessGesture), this, new InkCanvasGestureEventArgs(sc, results));

                    //Console.WriteLine(results[0].ApplicationGesture);
      
                }
                this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Render, new removeStroke(removeInkStroke),this.gestureLines[CurrentMapping]);
            }         
        }

        void m_TouchHandler_ContactMove(int x, int y, int z, int ID)
        {
            //if (ID == FIRST_TOUCH_ID)
            //{
            //    if(x==secondTouchX&&y==secondTouchY)    
            //    return;
            //    else
            //    {
            //        firstTouchX = x;
            //        firstTouchY = y;
            //    }
            //}
            //if (ID == 257)
            //{
            //  if(x==firstTouchX&&y==firstTouchY)
            //    return;
            //    else
            //    {
            //        secondTouchX = x;
            //        secondTouchY = y;
            //    }
            //}

            //if (ID == FIRST_TOUCH_ID)
            //{
              
            //    Core.InputDevices.Mouse.Instance.Location = new System.Drawing.Point((int)(x - 10), (int)(y - 10));

            //}

            //System.Windows.Point p = new System.Windows.Point(x * offsetX, y * offsetY);
           
            //if (ID == 257)
            //{
            //    OnTouchMove(p);
            //}
            //if (touchCardMapping.ContainsKey(ID)&&touchCardMapping[ID] != null)
            //{
            //    DisplayObject activatedCard = touchCardMapping[ID];
             
            //    if (ID == 257)
            //    this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Render, new OnTouchEvent(activatedCard.OnTouchMove), p);

            //    return;
            //}

            if (ID == firstTouchID)
            {
                Core.InputDevices.Mouse.Instance.Location = new System.Drawing.Point(x, y);
            }

            System.Windows.Point p = new System.Windows.Point(x * offsetX, y * offsetY);

            if (touchCardMapping.ContainsKey(ID) && touchCardMapping[ID] != null)
            {
                DisplayObject activatedCard = touchCardMapping[ID];

                this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Render, new OnTouchEvent(activatedCard.OnTouchMove), p);

                return;
            }
          
            int CurrentMapping = FindMappingIndex(ID);
            if (-1 != CurrentMapping)
            {

                StylusPoint start = GestureStrokes[CurrentMapping].StylusPoints[GestureStrokes[CurrentMapping].StylusPoints.Count - 1];
      
                GestureStrokes[CurrentMapping].StylusPoints.Add(new StylusPoint(p.X, p.Y));
 
                this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Render, new drawStroke(drawInkStroke),new Point(start.X,start.Y), p,this.gestureLines[CurrentMapping]);
                
            }    
        }

        private void OnTouchMove(Point p)
        {
            if (Persister is AsyncXMLSocketPersister && SendMouseMoveInfoEnabled)
            {
                if (this.secondMouseMoveNumber == this.NUM_SKIP_MOUSE_MOVE)
                {
                    Persister.MouseMove(new MouseMoveDataObject(0, 257,"Second", p.X / Properties.Settings.Default.Scale, p.Y / Properties.Settings.Default.Scale, MouseMoveConstants.PURE_MOUSEMOVE, 0L));
                    this.secondMouseMoveNumber = 0;
                }
                else
                {
                    this.secondMouseMoveNumber++;
                }
            }
        }

        private void drawInkStroke(Point start, Point end, Collection<Line> lineCollection)
        {
            Line connectingLine = new Line();
            connectingLine.Stroke = Brushes.YellowGreen;
            connectingLine.StrokeThickness = 3;
            connectingLine.X1 = start.X;
            connectingLine.X2 = end.X ;
            connectingLine.Y1 = start.Y;
            connectingLine.Y2 = end.Y ;
            this.windowCanvas.Children.Add(connectingLine);
            lineCollection.Add(connectingLine);
        }

        private void removeInkStroke(Collection<Line> deletedLines)
        {
            foreach (Line line in deletedLines)
            {
                this.windowCanvas.Children.Remove(line);
            }
            deletedLines.Clear();
        //    Console.WriteLine("delete");
        }

        #endregion

        //return the top artefact of the Point(X,Y)
        private DisplayObject getCurrentArtefact(Point point)
        {
 
            HitTestResult result = VisualTreeHelper.HitTest(this.windowCanvas, point);
            if (result == null)
                return null;

            DependencyObject visualComponent = result.VisualHit;
            if (visualComponent is DrawingVisual)
                visualComponent = VisualTreeHelper.GetParent(visualComponent);

            FrameworkElement result2 = visualComponent as FrameworkElement;
            while (result2!=null&&result2 != this)
            {

                if (result2 is DisplayObject)
                {
                    return (DisplayObject)result2;

                }

                if (((FrameworkElement)result2).DataContext != null && ((FrameworkElement)result2).DataContext is DisplayObject)
                    return (DisplayObject)(((FrameworkElement)result2).DataContext);
                if (LogicalTreeHelper.GetParent(result2) == null || LogicalTreeHelper.GetParent(result2).Equals(result2))
                {
                    return null;
                }

                result2 = result2.Parent as FrameworkElement;
            }
            return null;

     
        }

        

    }
}